using math

class MatDslPluginTest: Test {

	Void testDsl() {
		// Says: MatTest.fan(7,10): Internal error in DslPlugin 'math::MatDslPlugin': sys::Err: Unsupported literal type sys::Int
		// mat := Mat <|
		//	1 2
		//	3 4
		//|>
		// m2 := Mat<|1 2; 3 4|>
		// verifyEq(m1, m2)
		// m2 = Mat<|1, 2; 3, 4|>
		// verifyEq(m1, m2)
		// Random thoughts:
		// v := 3
		// b := Mat<|1 2; v 4|>
		// b := Mat("1 2; $v 4")
	}

}

**
** TODO Randomize these tests.
**
class MatTest: Test {

	Void testCreateOf() {
		m1 := Mat.from([[1, 2], [3, 4]])
		m2 := Mat.createOf(Int#, [2, 2], [1, 2, 3, 4])
		verifyEq(m1, m2)
		verifyErr(Err#) {
			// The shape doesn't match the list size.
			Mat.createOf(Int#, [2, 3], [1, 2, 3, 4])
		}
	}

	Void testEye() {
		eye := Mat.eye(3)
		verifyEq(Mat.from([[1f, 0f, 0f], [0f, 1f, 0f], [0f, 0f, 1f]]), eye)
	}

	Void testFrom() {
		mat := Mat.from([[1, 2], [3, 4]])
		verifyEq(1, mat.geti(0, 0));
		verifyEq(2, mat[[0, 1]]);
		verifyEq(3, mat.geti(1, 0));
		verifyEq(4, mat.geti(1, 1));
	}

	Void testMap() {
		mat := Mat.from([[1f, 2f], [3f, 4f]])
		mat.map(Float#) |Float v -> Float| {v.sin}
		mapped := mat.mapf{it.cos}
	}

	Void testMult() {
		a := Mat.from([[1, 2], [3, 4]])
		b := Mat.from([[3, 0], [1, 3]])
		c := a * b
		verifyEq(c, Mat.from([[5, 6], [13, 12]]))
		// Thoughts on '.*':
		// d := a.multEach(b)
		// d := a.mapWith(b) |i, j| {a * b}
		// d := a.map |v, i| {v * b[i]}
		// Thoughts on '\':
		// d := a.solve(b)
		// d := a.leftDiv(b)
		// d := a.divLeft(b)
		// d := a.invMult(b)
	}

	Void testMultEach() {
		a := Mat.from([[1, 2], [3, 4]])
		b := Mat.from([[3, 0], [1, 3]])
		c := a.multEach(b)
		verifyEq(c, Mat.from([[3, 0], [3, 12]]))
	}

	Void testMultFloat() {
		a := Mat.from([[1f, 2f], [3f, 4f]])
		b := a.multFloat(1.5f)
		// No need even for epsilon-off tests when sticking to purty powers of two.
		verifyEq(b, Mat.from([[1.5f, 3f], [4.5f, 6f]]))
	}

	Void testPlus() {
		a := Mat.from([[1, 2], [3, 4]])
		b := Mat.from([[3, 0], [1, 3]])
		c := a + b
		verifyEq(c, Mat.from([[4, 2], [4, 7]]))
		// TODO Move toStr checking to a separate method, and actually check the results instead of echo.
		echo(c)
	}

	Void testZeros() {
		zeros := Mat.zeros(5)
		verifyEq([5, 5], zeros.shape)
		zeros.size.times {
			verifyEq(0f, zeros.getf(it))
		}
	}

}
